/**
 * Copyright &copy; 2013-2015 山东易科德软件有限公司 All rights reserved.
 */
package cn.net.ecode.common.service;

import java.util.List;

import org.apache.ibatis.binding.BindingException;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import cn.net.ecode.common.config.Global;
import cn.net.ecode.common.persistence.TreeDao;
import cn.net.ecode.common.persistence.TreeEntity;
import cn.net.ecode.common.utils.StringUtils;

/**
 * Service基类
 * @author ThinkGem
 * @version 2014-8-19
 */
@Transactional(readOnly = true)
public abstract class TreeService<D extends TreeDao<T>, T extends TreeEntity<T>> extends CrudService<D, T> {
	
	@Override
	public List<T> findList(T entity) {
		// 传递ParentCode获取子节点，而传递ParentCodes将获取所有子节点
		// 如果传递ParentCodes又传递了主键Code则包含主键这条记录和子节点。
		if (StringUtils.isNotBlank(entity.getParentCodes())){
			entity.setParentCode(null);// 与codes互斥，只能设置一个。
			entity.setParentCodes("%," + entity.getParentCodes() + ",%");
		}
		return super.findList(entity);
	}
	
	/**
	 * 保存数据（插入或更新）
	 */
	@Transactional(readOnly = false)
	public void save(T entity) {
		
		// 先读取修改前的实体，用于更新修改前的hasnext字段
		T oldEntity = super.get(entity);
		
		// 如果没有设置父节点，则代表为跟节点，有则获取父节点实体
		if (entity.getParent() == null || StringUtils.isBlank(entity.getParentCode()) 
				|| TreeEntity.ROOT_CODE.equals(entity.getParentCode())){
			entity.setParent(null);
		}else{
			entity.setParent(super.get(entity.getParentCode()));
		}
		if (entity.getParent() == null){
			T parentEntity = null;
			try {
				parentEntity = entityClass.getConstructor(String.class).newInstance(TreeEntity.ROOT_CODE);
			} catch (Exception e) {
				throw new ServiceException(e);
			}
			entity.setParent(parentEntity);
			entity.getParent().setParentCodes(StringUtils.EMPTY);
		}
		
		// 获取修改前的parentIds，用于更新子节点的parentIds
		String oldParentIds = entity.getParentCodes(); 
		
		// 设置新的父节点串
		entity.setParentCodes(entity.getParent().getParentCodes()+entity.getParentCode()+",");
		
		// 设置数的层次级别（从0开始）
		entity.setSortGrade(entity.getParentCodes().replaceAll("[^,]", "").length() - 1);

		// 如果是新增，一定没有下级
		if (entity.getIsNewRecord()){
			entity.setHasnext(Global.NO);
		}
		
		// 预留接口事件，保存前调用
		preSave(entity);
		
		// 保存或更新实体
		super.save(entity);

		// 更新子节点 parentIds、sortGrede
		T o = null;
		try {
			o = entityClass.newInstance();
		} catch (Exception e) {
			throw new ServiceException(e);
		}
		o.setParentCodes("%,"+entity.getId()+",%");
		List<T> list = dao.findByParentCodesLike(o);
		for (T e : list){
			if (e.getParentCodes() != null && oldParentIds != null){
				e.setParentCodes(e.getParentCodes().replace(oldParentIds, entity.getParentCodes()));
				e.setSortGrade(e.getParentCodes().replaceAll("[^,]", "").length() - 1);
				preUpdateChild(entity, e); // 预留接口事件，更新子节前调用
				updateParentCodes(e); 		// 更新 parentCodes 和 sortGrade
			}
		}
		
		// 更新修改之前，父级的hasnext字段
		if (oldEntity != null && oldEntity.getParent() != null){
			updateHasnext(oldEntity.getParent());
		}
		
		// 更新当前节点，父级的hasnext字段
		if (entity != null && entity.getParent() != null && !StringUtils.equals(entity.getParentCode(),
				oldEntity == null ? "" : oldEntity.getParentCode())){
			updateHasnext(entity.getParent());
		}
	}
	
	/**
	 * 删除数据
	 * @param entity
	 */
	@Transactional(readOnly = false)
	public void delete(T entity) {
		super.delete(entity);
		// 更新父级的hasnext字段
		if (entity != null && entity.getParent() != null){
			updateHasnext(entity.getParent());
		}
	}

	/**
	 * 更新ParentCodes、SortGrade字段值
	 */
	@Transactional(readOnly = false, isolation = Isolation.READ_UNCOMMITTED) // 可读取未提交数据
	private void updateParentCodes(T entity){
		if (TreeEntity.ROOT_CODE.equals(entity.getId())){
			return;
		}
		try{
			dao.updateParentCodes(entity);
		}catch(BindingException ex){
			logger.warn("", ex);
		}
	}

	/**
	 * 更新Hasnext字段值
	 */
	@Transactional(readOnly = false, isolation = Isolation.READ_UNCOMMITTED) // 可读取未提交数据
	private void updateHasnext(T entity){
		if (TreeEntity.ROOT_CODE.equals(entity.getId())){
			return;
		}
		try{
			dao.updateHasnext(entity);
		}catch(BindingException ex){
			logger.warn("", ex);
		}
	}
	
	/**
	 * 修正本表树结构的所有父级编号
	 * 包含：数据修复（parentCodes、hasnext、sortGrade）字段
	 */
	@Transactional(readOnly = false) // 可读取未提交数据
	public void updateFixParentCodes(){
		updateFixParentCodes(T.ROOT_CODE);
	}
	
	/**
	 * 按父级编码修正树结构的所有父级编号
	 * 包含：数据修复（parentCodes、hasnext、sortGrade）字段
	 */
	@Transactional(readOnly = false) // 可读取未提交数据
	public void updateFixParentCodes(String parentCode){
		T e = newEntity();
		e.setStatus(null);
		e.setParentCode(parentCode);
		List<T> l = dao.findList(e);
		updateFixParentCodes(l, e.getParentCode(), StringUtils.EMPTY);
	}
	
	/**
	 * 修正指定节点及下级节点的所有父级编号（这是个递归程序）
	 */
	private void updateFixParentCodes(List<T> list, String parentCode, String parentCodes){
		for (T entity : list){
			entity.setParentCodes(parentCodes+parentCode+",");
			entity.setSortGrade(entity.getParentCodes().replaceAll("[^,]", "").length() - 1);
			updateParentCodes(entity); // 更新 parentCodes 和 sortGrade
			updateHasnext(entity); 	   // 更新 hasnext
			// 有下级，则更新下级节点
			T e = newEntity();
			e.setStatus(null);
			e.setParentCode(entity.getId());
			List<T> l = dao.findList(e);
			if (l.size() > 0){
				updateFixParentCodes(l, e.getParentCode(), entity.getParentCodes());
			}
		}
	}
	
	/**
	 * 预留接口事件，保存前调用
	 */
	protected void preSave(T entity) {
		
	}
	
	/**
	 * 预留接口事件，更新子节前调用
	 * @param childEntity
	 */
	protected void preUpdateChild(T entity, T childEntity) {
		
	}

}
